這邊寫了一個蠻常用的 hook 種類 useFetchUsers()
import axios from 'axios';
import { useState, useEffect } from 'react';
interface User {
id: string;
username: string;
}
function useFetchUsers() {
const [users, setUsers] = useState<User[]>([]);
const fetchUsers = async () => {
const result = await axios.get<User[]('https://jsonplaceholder.typicode.com/users');
setUsers(result.data);
};
useEffect(() => {
fetchUsers();
}, []);
return users;
}
export default useFetchUsers;
那我們來寫他的測試吧,因為有 axios 跟 Promise 所以這次會用到
jest.spyOn
:模擬 axios 會用到的由於這次 fetchUsers 只有是否有資料這兩個 case 要測試 ,按照 hook 的 return ,當 API 有問題時會回傳預設值空陣列
import axios from 'axios';
import { renderHook, waitFor } from '@testing-library/react';
import useFetchUsers from './index';
describe('測試 useFetchUsers', () => {
it('fetches and returns users', async () => {
const mock = jest.spyOn(axios, 'get');
mock.mockResolvedValueOnce({
data: [
{ id: '1', username: 'Dylan' },
{ id: '2', username: 'John' },
],
});
const hook = renderHook(() => useFetchUsers());
await waitFor(() => {
expect(hook.result.current).toEqual([
{ id: '1', username: 'Dylan' },
{ id: '2', username: 'John' },
]);
});
});
it('if error return empty array ', async () => {
const mock = jest.spyOn(axios, 'get');
mock.mockRejectedValueOnce(new Error('error'));
const hook = renderHook(() => useFetchUsers());
await waitFor(() => {
expect(hook.result.current).toEqual([]);
});
});
});
測試 useFetchUsers
✓ fetches and returns users (72 ms)
✓ if error return empty array (44 ms)
Test Suites: 3 passed, 3 total
Tests: 8 passed, 8 total
Snapshots: 0 total
先利用 jest.spyOn
模擬 axios.get 要拿到的資料,後面再使用 waitFor()
等待Promise完成,有call api 的 hook 大多都可以這樣測試
waitFor
注意事項waitFor 雖然好用,但有幾點需要注意
waitFor
//不好的寫法
await waitFor(() => {})
expect(window.fetch).toHaveBeenCalledWith('foo')
expect(window.fetch).toHaveBeenCalledTimes(1)
// 好的寫法
await waitFor(() => expect(window.fetch).toHaveBeenCalledWith('foo'))
expect(window.fetch).toHaveBeenCalledTimes(1)
waitFor
裡執行 side Effects
//不好的寫法
await waitFor(() => {
const hook = renderHook(() => useFetchUsers());
expect(hook.result.current).toEqual([
{ id: '1', username: 'Dylan' },
{ id: '2', username: 'John' },
]);
});
//好的寫法
const hook = renderHook(() => useFetchUsers());
await waitFor(() => {
expect(hook.result.current).toEqual([
{ id: '1', username: 'Dylan' },
{ id: '2', username: 'John' },
]);
});
waitFor
內有多個斷言 (assertions)//不好的寫法
await waitFor(() => {
expect(window.fetch).toHaveBeenCalledWith('foo')
expect(window.fetch).toHaveBeenCalledTimes(1)
})
// 好的寫法
await waitFor(() => expect(window.fetch).toHaveBeenCalledWith('foo'))
expect(window.fetch).toHaveBeenCalledTimes(1)
今天的測試就先到這,明天再一起看看更多測試吧!
waitFor()
注意事項參考這位大神的文章